﻿using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using log4net;
using log4net.Layout;
using log4net.Appender;
using log4net.Repository.Hierarchy;
using log4net.Core;
using log4net.Config;
using OneCard.Face8280Module.DeviceModel.Model.Log;

namespace OneCard.Face8280Module.Controllers
{
    public class FaceAPILogResourceMiddleware
    {

        private readonly Dictionary<string, string> PathNames;
        private HashSet<string> Headerfilter = new HashSet<string>();
        private readonly RequestDelegate next;

        private static JsonSerializerSettings JsonSettings = new JsonSerializerSettings()
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            DateFormatString = "yyyy-MM-dd HH:mm:ss",
            NullValueHandling = NullValueHandling.Ignore

        };

        private class APIContext
        {
            public string APIName = string.Empty;
            public string IPAddr = string.Empty;
            public string URL = string.Empty;
            public string DeviceSN = string.Empty;
            public string RequestID = string.Empty;
            public ILog Log;
        }


        public FaceAPILogResourceMiddleware(RequestDelegate next)
        {
            PathNames = new Dictionary<string, string>();
            //PathNames.Add("note/insertNoteFace", "上传打卡记录");
            //PathNames.Add("device/updateStateDevice", "设备心跳包");
            PathNames.Add("devicePass/selectPassInfo", "拉取人员");
            PathNames.Add("devicePass/setPassResult", "拉取人员反馈");
            PathNames.Add("devicePass/selectDeleteInfo", "删除人员");
            PathNames.Add("devicePass/setDeleteResult", "删除人员反馈");
            PathNames.Add("device/selectRestart", "远程操作");
            //PathNames.Add("parameter/inertParameter", "上传参数");
            //PathNames.Add("parameter/selectParameterInfo", "拉取参数");



            Headerfilter.Add("Cache-Control");
            Headerfilter.Add("Connection");
            Headerfilter.Add("Pragma");
            Headerfilter.Add("Accept");
            Headerfilter.Add("Accept-Language");
            Headerfilter.Add("User-Agent");

            this.next = next;
        }


        public async Task Invoke(HttpContext context)
        {
            var Request = context.Request;
            bool bExecuting = false;
            APIContext api = null;
            var sAPIPath = Request.Path.Value;


            if (PathNames.ContainsKey(sAPIPath.Substring(1)))
            {
                bExecuting = true;
            }
            if (bExecuting)
            {
                api = new APIContext();

                OnResourceExecuting(context, api);
            }
            await next.Invoke(context);

            if (bExecuting)
                await OnResourceExecuted(context, api);
        }

        private async Task OnResourceExecuted(HttpContext context, APIContext api)
        {
            //处理执行其他中间件后的ResponseBody
            var http = context;
            var Response = http.Response;
            var ret = http.Request;

            if (string.IsNullOrEmpty(api.DeviceSN)) return;

            ConnectIOLog ResponseLog = new ConnectIOLog()
            {
                HttpType = "响应",

                URL = api.APIName + "  " + api.URL,
                ContentLength = string.Empty,
                ContentType = "application/json; charset=utf-8",
                Body = null
            };

            //var obj = JsonConvert.SerializeObject(Result, JsonSettings);

            if (!Response.ContentLength.HasValue)
            {
                Response.ContentLength = Response.Body.Length;
            }


            string responseBody = string.Empty;
            Response.Body.Position = 0;
            using (var responseReader = new StreamReader(Response.Body, Encoding.UTF8, true, -1, true))
            {
                responseBody = await responseReader.ReadToEndAsync();
            }

            ResponseLog.Body = JsonConvert.DeserializeObject(responseBody);
            ResponseLog.ContentLength = Response.ContentLength.ToString();
            Response.Body.Position = 0;
            api.Log.Info(JsonConvert.SerializeObject(ResponseLog, Formatting.Indented));



        }

        private void OnResourceExecuting(HttpContext context, APIContext api)
        {
            var http = context;
            var ret = http.Request;
            api.URL = ret.Path;


            var sAPIPath = api.URL;

            sAPIPath = sAPIPath.Substring(1);
            if (PathNames.ContainsKey(sAPIPath))
            {
                api.APIName = PathNames[sAPIPath];
            }
            Dictionary<string, string> headers = new Dictionary<string, string>();

            //Headerfilter.Add("Host");
            foreach (var item in ret.Headers.Keys)
            {
                if (!Headerfilter.Contains(item))
                    headers.Add(item, ret.Headers[item].ToString());
            }


            ret.EnableBuffering();

            //X-Forwarded-For
            if (ret.Headers.ContainsKey("X-Forwarded-For"))
            {
                api.IPAddr = ret.Headers["X-Forwarded-For"].ToString();
            }
            else
                api.IPAddr = $"{http.Connection.RemoteIpAddress}:{http.Connection.RemotePort}";
            var sHost = string.Empty;
            if (ret.Headers.ContainsKey("Host"))
                sHost = ret.Headers["Host"].ToString();
            api.URL = $"{sHost}{api.URL}";
            ConnectIOLog RequestLog = new ConnectIOLog()
            {
                HttpType = "请求",
                URL = $"{api.APIName} -- {api.URL}",
                ContentLength = string.Empty,
                ContentType = string.Empty,
                Body = string.Empty
            };

            if (ret.ContentLength.HasValue)
            {
                RequestLog.ContentType = ret.ContentType;
                RequestLog.ContentLength = ret.ContentLength.Value.ToString();


                try
                {
                    http.Request.Body.Position = 0;
                    using (var requestReader = new StreamReader(ret.Body, encoding: Encoding.UTF8, leaveOpen: true))
                    {
                        var requestContent = requestReader.ReadToEndAsync().Result;
                        RequestLog.Body = requestContent;
                        try
                        {
                            //尝试读取
                            var dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(requestContent);
                            if (dic.ContainsKey("deviceId"))
                            {
                                api.DeviceSN = dic["deviceId"].ToString();
                            }
                            if (string.IsNullOrEmpty(api.DeviceSN)) return;
                            RequestLog.Body = dic;
                        }
                        catch (Exception)
                        {


                        }
                    }
                }
                catch (Exception ex)
                {

                    RequestLog.Body = $"{{\"err\":\"读取Body时发生错误！{ex.ToString()}\"}}";
                }

                http.Request.Body.Position = 0;

                var log = GetLoggerByName(api.DeviceSN);
                api.Log = log;
                log.Info(JsonConvert.SerializeObject(RequestLog, Formatting.Indented));
            }

        }


        public static ILog GetLoggerByName(string name)
        {
            if (LogManager.Exists(name) == null)
            {

                // Pattern Layout defined
                PatternLayout patternLayout = new PatternLayout();
                //patternLayout.ConversionPattern = "%date %thread %level %logger - %message%newline";
                patternLayout.ConversionPattern = "%date - %message%newline";
                patternLayout.ActivateOptions();

                // configurating the RollingFileAppender object
                RollingFileAppender appender = new RollingFileAppender();
                appender.Name = name;
                appender.AppendToFile = true;
                appender.File = $"Log\\{name}.log";
                appender.StaticLogFileName = true;
                appender.PreserveLogFileNameExtension = true;
                appender.LockingModel = new FileAppender.MinimalLock();
                appender.Layout = patternLayout;
                appender.MaxSizeRollBackups = 512;
                appender.MaximumFileSize = "10MB";
                appender.RollingStyle = RollingFileAppender.RollingMode.Composite;
                appender.ActivateOptions();

                Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();

                var loger = hierarchy.GetLogger(name, hierarchy.LoggerFactory); //!!! 此处写法是重点，不容更改
                loger.Hierarchy = hierarchy;
                loger.RemoveAllAppenders();
                loger.AddAppender(appender);
                loger.Level = Level.All;

                BasicConfigurator.Configure();//!!! 此处写法是重点，不容更改
            }
            var log = LogManager.GetLogger(name);
            return log;
        }
    }






}
